///////////////////////////////////////////////////////////
///////////////// Have an itch? Scratch it! ///////////////
///////////////////////// SCRATCH /////////////////////////
/////////////////////  A MUD  Server   ////////////////////
///////////////////// By: Jared Devall ////////////////////
/////////////////////      Thanks:     ////////////////////
/////////////////////  DIKU/Merc/ROM   ////////////////////
///////////////////// Aetas/Deus Gang  ////////////////////
/////////////////////       Beej       ////////////////////
///////////////////////////////////////////////////////////

#include "definitions.h"
#include <list>
#include "commands.h"
#include "commandTable.h"
#include "character.h"
#include "world.h"
#include "stringutil.h"
#include "split.h"
#include "timestamp.h"
#include "logs.h"
#include "functions.h"

using namespace std;

// Command definitions for commands beginning with the letters Q through S
// (Keep in alphabetical order... it's MUCH easier)
CmdQuit::CmdQuit( ) {
	SetName( "quit" );
	SetLevel( 1 );
	SetEnabled( true );
	SetOmniset( true );
}

bool CmdQuit::Execute( Character* c, const string &args ) {
	string buf;

	log( c->getName(), c->getLevel(), "logged out" );
	
	buf << c->getName() << " has quit.";
	World::Instance().Omninet( buf, STANDARD, NULL, false );
	
	c->SetDisconnected( true );
	return true;
}

CmdReboot::CmdReboot( ) {
	SetName( "reboot" );
	SetLevel( HEAD );
	SetEnabled( true );
	SetOmniset( true );
}

bool CmdReboot::Execute( Character* c, const string &args ) {
	World::Instance().Copyover();
	return true;
}

CmdRedit::CmdRedit() {
	SetName( "redit" );
	SetLevel( BUILDER );
	SetEnabled( true );
	SetOmniset( false );
}

bool CmdRedit::Execute( Character* c, const string& args ) {

	if ( c->getRoom()->getArea()->getPermission( c->getId() ) || c->getLevel() >= HEAD ) {
		c->SetStatus( REDIT );
		c->Send( "Welcome to Symphony Edit Mode (SEM) for Rooms!\n\rFor a list of available commands in redit mode, type \"commands\"\n\r" );
	} else {
		c->Send( "You don't have permissions for this room.\n\r" );
	}

	return true;
}

CmdReply::CmdReply( ) {
	SetName( "reply" );
	SetLevel( 1 );
	SetEnabled( true );
	SetOmniset( false );
}

bool CmdReply::Execute( Character* c, const string &args ) {
	string name;
	string message;
	Character* target;

	if ( ( target = World::Instance().FindCharacter( c->getReply() ) ) == NULL ) {
		c->Send( "That target cannot be found.\n\r" );
		return false;
	}

	message << c->getName() << " tells you '{Y" << args << "{x'\n\r";
	target->Send( message );
	target->setReply( c->getName() );
	message.erase();
	message << "You tell " << target->getName() << " '{Y" << args << "{x'\n\r";
	c->Send( message );
	return true;
}

CmdSave::CmdSave() {
	SetName( "save" );
	SetLevel( 1 );
	SetEnabled( true );
	SetOmniset( false );
}

bool CmdSave::Execute( Character* c, const string &args ) {
	c->cSave();
	c->Send( "Your data has been saved.\n\r" );
	return true;
}

CmdSay::CmdSay( ) {
	SetName( "say" );
	SetShortcut( "'" );
	SetLevel( 1 );
	SetEnabled( true );
	SetOmniset( false );
}

bool CmdSay::Execute( Character* c, const string &args ) {
	string args1;
	string buf1;
	string buf2;
	Character* target = 0;

	if ( args.empty() )
		return true;

	if ( args.length() > 500 ) {
		args1.append( args, 0, 500 );
	} else {
		args1 = args;
	}
	rtrim( args1, args1 );

	buf1 << "You say, '{G" << args1 << "{x'\n\r";
	buf2 << c->getName() << " says '{G" << args1 << "{x'\n\r";

	c->Send( buf1 );
	for ( std::list< Character* >::iterator it = World::Instance().getClist().begin(); it != World::Instance().getClist().end(); it++ ) {
		target = *it;
		if ( target->getRoom() == c->getRoom() && target != c )
			target->Send( buf2 );
	}

	return true;
}

CmdScore::CmdScore() {
	SetName( "score" );
	SetLevel( 1 );
	SetEnabled( true );
	SetOmniset( false );
}

bool CmdScore::Execute( Character* c, const string& args ) {
	std::string temp; // for format()
	std::string score;
	
	score << " ___________________________________________________________________________\n\r";
	score << "|\\_________________________________________________________________________/|\n\r";
	score << "||Name:  " << format( 12, c->getName(), temp, 'c' );
	score << " " << format( 12, c->GetLname(), temp, 'c' );
	score << " ||level: " << format( 3, c->getLevel(), temp, 'Y' );
	score << "       ||gender: " << format( 6, c->stringGender(), temp, 'B' ) << "     ||\n\r";
	score << "||Race:  " << format( 12, c->stringRace(), temp, 'c' );
	score << "              ||hp:    " << format( 4, c->getHp(), temp, 'G' );
	score << "/" << format( 4, c->getMhp(), temp, 'g' );
	score << " ||hand:   " << format( 5, c->stringHand(), temp, 'B' ) << "      ||\n\r";
	score << "||Class: " << format( 12, c->stringClass(), temp, 'c' );
	score << "              ||mana:  " << format( 4, c->getMana(), temp, 'C' );
	score << "/" << format( 4, c->getMmana(), temp, 'c' ) << " ||height: ";
	score << format( 10, c->getHeight(), temp, 'B' ) << " ||\n\r";
	score << "||Clan:  " << format( 12, c->GetClan(), temp, 'c' );
	score << "              ||move:  " << format( 4, c->getMove(), temp, 'B' );
	score << "/" << format( 4, c->getMmove(), temp, 'b' );
	score << " ||weight: " << format( 10, c->getWeight(), temp, 'B' ) << " ||\n\r";
	score << "||_________________________________||_________________||___________________||\n\r";
	score << "||_________________________________________________________________________||\n\r";
	score << "||hr/dr: " << format( 3, c->getHr(), temp, 'R' );
	score << "/" << format( 3, c->getDr(), temp, 'R' );
	score << "                  ||str: " << format( 2, c->getStr(), temp, 'G' );
	score << "/" << format( 2, c->getMstr(), temp, 'g' );
	score << "     ||age:    " << format( 4, c->getAge(), temp, 'M' ) << "          ||\n\r";
	score << "||saves: " << format( 5, c->getSaves(), temp, 'R' );
	score << "                    ||dex: " << format( 2, c->getDex(), temp, 'G' );
	score << "/" << format( 2, c->getMdex(), temp, 'g' );
	score << "     ||tnl:    " << format( 7, c->GetTnl(), temp, 'M' ) << "       ||\n\r";
	score << "||                                ||con: " << format( 2, c->getCon(), temp, 'G' );
	score << "/" << format( 2, c->getMcon(), temp, 'g' );
	score << "     ||exp:    " << format( 6, c->GetExp(), temp, 'M' ) << "        ||\n\r";
	score << "||        ac: " << format( 4, c->getAc(), temp, 'R' );
	score << "                ||int: " << format( 2, c->getIntel(), temp, 'G' );
	score << "/" << format( 2, c->getMintel(), temp, 'g' );
	score << "     ||pracs:  " << format( 4, c->GetPracs(), temp, 'M' );
	score << "          ||\n\r";
	score << "||  bash:   " << format( 4, c->getAcbash(), temp, 'R' );
	score << " slash:  " << format( 4, c->getAcslash(), temp, 'R' );
	score << "     ||wis: " << format( 2, c->getWis(), temp, 'G' );
	score << "/" << format( 2, c->getMwis(), temp, 'g' );
	score << "     ||trains: " << format( 4, c->GetTrains(), temp, 'M' ) << "          ||\n\r";
	score << "||  pierce: " << format( 4, c->getAcpierce(), temp, 'R' );
	score << " exotic: " << format( 4, c->getAcexotic(), temp, 'R' );
	score << "     ||cha: " << format( 2, c->getCha(), temp, 'G' );
	score << "/" << format( 2, c->getMcha(), temp, 'g' );
	score << "     ||gains:  " << format( 4, c->GetGains(), temp, 'M' ) << "          ||\n\r";
	score << "||________________________________||_______________||______________________||\n\r";
	score << "||_________________________________________________________________________||\n\r";
	score << "||gold: " << format( 8, c->getGoldheld(), temp, 'Y' );
	score << "        ||items: " << format( 4, c->getInventory().size(), temp, 'm' );
	score << "  weight: " << format( 6, c->getWeight(), temp, 'm' ) << "                      ||\n\r";
	score << "||silver: " << format( 8, c->getSilverheld(), temp, 'W' );
	score << "      ||points: " << format( 6, c->GetPoints(), temp, 'm' ) << "                                   ||\n\r";
	score << "||bank: " << format( 7, c->GetBankgold(), temp, 'Y' );
	score << "/" << format( 7, c->GetBanksilver(), temp, 'W' );
	score << " ||house: " << format( 41, c->GetHouse(), temp, 'm' ) << " ||\n\r";
	score << "||______________________||_________________________________________________||\n\r";
	score << "|/_________________________________________________________________________\\|\n\r";

	c->Send( score );
	return true;
}

CmdShutdown::CmdShutdown( ) {
	SetName( "shutdown" );
	SetLevel( HEAD );
	SetEnabled( true );
	SetOmniset( true );
}

bool CmdShutdown::Execute( Character* c, const string &args ) {
	string buf;
	
	buf << "## Scratch is being shutdown.\n\r";	
	World::Instance().Broadcast( buf, WCONNECTED );
	World::Instance().Die();
	return true;
}

CmdSiteban::CmdSiteban() {
	SetName( "siteban" );
	SetLevel( HEAD );
	SetEnabled( true );
	SetOmniset( true );
}

bool CmdSiteban::Execute( Character* c, const string& args ) {
	std::string buf;
	std::list< Character* >::iterator c_it;
	std::list< std::string* >::iterator s_it;
	std::string ip;

	if ( args.empty() ) {
		c->Send( "syntax: siteban <name>   Disconnects user and adds their ip to the siteban list\n\r        siteban <ip>     Adds ip to the siteban list\n\r" );
		return false;
	} else if ( args == "list" ) {
		if ( World::Instance().getBanList().empty() ) {
			c->Send( "There are no listed sitebans at this time.\n\r" );
			return true;
		} else {
			for ( s_it = World::Instance().getBanList().begin(); s_it != World::Instance().getBanList().end(); s_it++ )
				buf << "  " << *(*s_it) << "\n\r";
			c->Send( buf );
			return true;
		}
	} else {
		for ( c_it = World::Instance().getClist().begin(); c_it != World::Instance().getClist().end(); c_it++ ) {
			if ( (*c_it)->getName() == args ) {
				World::Instance().addBannedIp( (*c_it)->GetSocket()->GetSocketIP() );
				buf << (*c_it)->getName() << " (" << (*c_it)->GetSocket()->GetSocketIP() << ") has been banned.\n\r";
				return true;
			}
		}
		World::Instance().addBannedIp( args );
		buf << "ip " << args << " has been banned.\n\r";
		c->Send( buf );
		return true;
	}

	c->Send( "error" );
	return false;
}

CmdSockets::CmdSockets( ) {
	SetName("sockets");
	SetLevel( GOD );
	SetEnabled( true );
	SetOmniset( false );
}

bool CmdSockets::Execute( Character* c, const string &args ) {
	string buf;
	list< Character* >::iterator it;
	buf << "\t\t-- Sockets --\n\r";
	for ( it = World::Instance().getClist().begin(); it != World::Instance().getClist().end(); ++it ) {
		buf << (*it)->getName() << " @ {C" << (*it)->GetSocket()->GetSocketHost() << "{x => {c" << (*it)->GetSocket()->GetSocketIP() << "{x (descriptor: {W" << (*it)->GetSocket()->GetDescriptor() << "{x)\n\r";
	}
	c->Send( buf );
	return true;
}

CmdSouth::CmdSouth() {
	SetName( "south" );
	SetLevel( 1 );
	SetEnabled( true );
	SetOmniset( false );
}

bool CmdSouth::Execute( Character* c, const std::string& args ) {
	std::string buf;
	std::string toMessage;
	std::string fromMessage;
	Exit* in = &( c->getRoom()->GetExit( SOUTH ) );
	
	if ( !in->GetThere() ) {
		buf << "There is no exit that way.\n";
		c->Send( buf );
		return true;
	}
	else if ( in->GetDoor() && !in->GetOpen() ) {
		buf << "That door is closed.\n";
		c->Send( buf );
		return true;
	}
	else {
		Room* from = c->getRoom();
		Room* to = 0;
		if ( ( to = World::Instance().FindRoom( in->GetPoint() ) ) == NULL ) {
			c->Send( "You can't go there.\n\r" );
			std::string message = "Exit inconsistency: ";
			message << from->GetVnum() << " south to " << in->GetPoint();
			log( SERVER, message );
			return false;
		}

		fromMessage << c->getName() << " has left to the south.";
		toMessage << c->getName() << " has arrived from the north.";

		from->Remove( c );
		sendToRoom( from, fromMessage );
		sendToRoom( to, toMessage );
		to->Add( c );
		c->setRoom( World::Instance().FindRoom( to->GetVnum() )->GetVnum() );
		CmdLook Command;
		Command.Execute( c, "auto_look: south" );
	}

	return true;
}
